/**
 * Python进程管理服务
 * 负责Python脚本的执行、进程管理和输出处理
 */

import * as childProcess from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { BrowserWindow } from 'electron';
import { pythonEnvironmentService } from './pythonEnvironmentService';

export interface PythonExecutionParams {
  scriptPath?: string;
  filePath?: string;
  fileName?: string;
  args?: any[];
  pluginName?: string;
}

export interface PythonExecutionResult {
  success: boolean;
  message?: string;
  data?: string;
  output?: string;
  error?: string;
}

export interface PythonLogOutput {
  type: 'stdout' | 'stderr';
  data: string;
  timestamp: string;
}

export interface PythonProcessEvent {
  code?: number | null;
  success?: boolean;
  error?: string;
  timestamp: string;
}

export interface PythonLogEntry {
  level: 'info' | 'warn' | 'error' | 'debug';
  message: string;
  timestamp: string;
  context?: string;
  details?: any;
}

export class PythonLogger {
  private static formatMessage(level: string, message: string, context?: string): string {
    const timestamp = new Date().toISOString();
    const contextStr = context ? `[${context}] ` : '';
    return `[${timestamp}] [${level.toUpperCase()}] ${contextStr}${message}`;
  }

  static info(message: string, context?: string, details?: any): void {
    console.log(this.formatMessage('info', message, context));
    if (details) console.log('Details:', details);
  }

  static warn(message: string, context?: string, details?: any): void {
    console.warn(this.formatMessage('warn', message, context));
    if (details) console.warn('Details:', details);
  }

  static error(message: string, context?: string, details?: any): void {
    console.error(this.formatMessage('error', message, context));
    if (details) console.error('Details:', details);
  }

  static debug(message: string, context?: string, details?: any): void {
    console.debug(this.formatMessage('debug', message, context));
    if (details) console.debug('Details:', details);
  }
}

export class PythonErrorHandler {
  static handleError(error: any, context: string): PythonExecutionResult {
    const errorMessage = error instanceof Error ? error.message : String(error);
    const fullMessage = `${context}: ${errorMessage}`;
    
    PythonLogger.error(fullMessage, context, error);
    
    return {
      success: false,
      error: errorMessage
    };
  }

  static handleProcessError(error: any, processId?: string): PythonExecutionResult {
    const context = processId ? `Python进程[${processId}]` : 'Python进程';
    return this.handleError(error, context);
  }

  static handlePathError(error: any, scriptPath?: string): PythonExecutionResult {
    const context = scriptPath ? `路径解析[${scriptPath}]` : '路径解析';
    return this.handleError(error, context);
  }
}

export class PythonProcessService {
  private static instance: PythonProcessService;
  private runningProcesses: Map<string, childProcess.ChildProcess> = new Map();
  private PLUGINS_DIR: string;

  private constructor(pluginsDir: string) {
    this.PLUGINS_DIR = pluginsDir;
  }

  public static getInstance(pluginsDir?: string): PythonProcessService {
    if (!PythonProcessService.instance) {
      if (!pluginsDir) {
        throw new Error('PythonProcessService需要pluginsDir参数进行初始化');
      }
      PythonProcessService.instance = new PythonProcessService(pluginsDir);
    }
    return PythonProcessService.instance;
  }

  /**
   * 解析和验证Python脚本路径
   */
  private resolveScriptPath(params: PythonExecutionParams): string {
    let scriptPath = params.scriptPath || params.filePath || params.fileName;
    
    if (!scriptPath) {
      throw new Error('未提供Python脚本路径');
    }

    // 标准化路径分隔符
    scriptPath = path.normalize(scriptPath);
    
    // 如果已经是绝对路径且存在，直接返回
    if (path.isAbsolute(scriptPath)) {
      if (fs.existsSync(scriptPath)) {
        return this.validatePythonFile(scriptPath);
      }
      throw new Error(`Python脚本不存在: ${scriptPath}`);
    }

    // 处理相对路径的多种情况
    const candidatePaths = this.generateCandidatePaths(scriptPath, params.pluginName);
    
    for (const candidatePath of candidatePaths) {
      if (fs.existsSync(candidatePath)) {
        console.log(`找到Python脚本: ${candidatePath}`);
        return this.validatePythonFile(candidatePath);
      }
    }

    // 如果所有候选路径都不存在，抛出详细错误
    const searchedPaths = candidatePaths.join('\n  - ');
    throw new Error(`Python脚本不存在。已搜索以下路径:\n  - ${searchedPaths}`);
  }

  /**
   * 生成候选路径列表
   */
  private generateCandidatePaths(scriptPath: string, pluginName?: string): string[] {
    const candidates: string[] = [];
    
    // 1. 插件目录路径（如果提供了插件名）
    if (pluginName) {
      if (scriptPath.startsWith('./')) {
        candidates.push(path.join(this.PLUGINS_DIR, pluginName, scriptPath.substring(2)));
      } else {
        candidates.push(path.join(this.PLUGINS_DIR, pluginName, scriptPath));
      }
    }
    
    // 2. 当前工作目录
    candidates.push(path.join(process.cwd(), scriptPath));
    
    // 3. 相对于PLUGINS_DIR的路径
    candidates.push(path.join(this.PLUGINS_DIR, scriptPath));
    
    // 4. 原始路径（可能是相对于执行目录的）
    candidates.push(scriptPath);
    
    // 去重
    return [...new Set(candidates)];
  }

  /**
   * 验证Python文件
   */
  private validatePythonFile(filePath: string): string {
    const stats = fs.statSync(filePath);
    
    if (!stats.isFile()) {
      throw new Error(`路径不是文件: ${filePath}`);
    }
    
    const ext = path.extname(filePath).toLowerCase();
    if (ext !== '.py' && ext !== '.pyw') {
      console.warn(`警告: 文件扩展名不是.py或.pyw: ${filePath}`);
    }
    
    return filePath;
  }

  /**
   * 生成进程ID
   */
  private generateProcessId(): string {
    return `python_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  /**
   * 发送日志输出到渲染进程
   */
  private sendLogOutput(event: Electron.IpcMainInvokeEvent, logOutput: PythonLogOutput): void {
    event.sender.send('python-log-output', logOutput);
  }

  /**
   * 发送进程事件到渲染进程
   */
  private sendProcessEvent(event: Electron.IpcMainInvokeEvent, eventType: string, eventData: PythonProcessEvent): void {
    event.sender.send(eventType, eventData);
  }

  /**
   * 执行Python脚本
   */
  public async executePythonScript(
    event: Electron.IpcMainInvokeEvent,
    params: PythonExecutionParams
  ): Promise<PythonExecutionResult> {
    const processId = this.generateProcessId();
    
    try {
      // 解析脚本路径
      const scriptPath = this.resolveScriptPath(params);
      const args = params.args || [];
      
      PythonLogger.info(`开始执行Python脚本: ${scriptPath}`, processId, { args, pluginName: params.pluginName });

      // 获取Python可执行文件路径
      const pythonPath = await pythonEnvironmentService.getPythonExecutablePath();
      if (!pythonPath) {
        throw new Error('未找到Python可执行文件，请确保Python已正确安装并添加到PATH环境变量中');
      }

      PythonLogger.debug(`使用Python路径: ${pythonPath}`, processId);

      return new Promise((resolve) => {
        const pythonProcess = childProcess.spawn(pythonPath, [scriptPath, ...args], {
          stdio: ['pipe', 'pipe', 'pipe'],
          env: { ...process.env, PYTHONUNBUFFERED: '1' }
        });
        
        // 存储进程引用
        this.runningProcesses.set(processId, pythonProcess);
        PythonLogger.debug(`Python进程已启动`, processId, { pid: pythonProcess.pid });
        
        let output = '';
        let errorOutput = '';

        // 处理stdout输出
        pythonProcess.stdout?.on('data', (data) => {
          const dataStr = data.toString();
          output += dataStr;
          
          this.sendLogOutput(event, {
            type: 'stdout',
            data: dataStr,
            timestamp: new Date().toISOString()
          });
        });

        // 处理stderr输出
        pythonProcess.stderr?.on('data', (data) => {
          const dataStr = data.toString();
          errorOutput += dataStr;
          
          this.sendLogOutput(event, {
            type: 'stderr',
            data: dataStr,
            timestamp: new Date().toISOString()
          });
        });

        // 处理进程结束
        pythonProcess.on('close', (code) => {
          // 清理进程引用
          this.runningProcesses.delete(processId);
          
          this.sendProcessEvent(event, 'python-process-ended', {
            code,
            success: code === 0,
            timestamp: new Date().toISOString()
          });
          
          if (code !== 0) {
            PythonLogger.error(`Python脚本执行失败，退出码: ${code}`, processId, { errorOutput, output });
            resolve({ 
              success: false, 
              error: errorOutput || `Python脚本执行失败，退出码: ${code}`,
              output: output
            });
          } else {
            PythonLogger.info(`Python脚本执行成功`, processId);
            resolve({ 
              success: true,
              message: '脚本执行成功',
              data: output
            });
          }
        });

        // 处理进程错误
        pythonProcess.on('error', (err) => {
          // 清理进程引用
          this.runningProcesses.delete(processId);
          
          this.sendProcessEvent(event, 'python-process-error', {
            error: err.message,
            timestamp: new Date().toISOString()
          });
          
          const result = PythonErrorHandler.handleProcessError(err, processId);
          resolve({
            success: false,
            error: `启动Python子进程失败: ${err.message}`
          });
        });
      });
    } catch (error: any) {
      return PythonErrorHandler.handlePathError(error, params.scriptPath || params.filePath || params.fileName);
    }
  }

  /**
   * 终止指定的Python进程
   */
  public terminateProcess(processId: string): boolean {
    const process = this.runningProcesses.get(processId);
    if (process && !process.killed) {
      process.kill('SIGTERM');
      this.runningProcesses.delete(processId);
      return true;
    }
    return false;
  }

  /**
   * 终止所有运行中的Python进程
   */
  public terminateAllProcesses(): void {
    for (const [processId, process] of this.runningProcesses) {
      if (!process.killed) {
        process.kill('SIGTERM');
      }
    }
    this.runningProcesses.clear();
  }

  /**
   * 获取运行中的进程数量
   */
  public getRunningProcessCount(): number {
    return this.runningProcesses.size;
  }

  /**
   * 获取所有运行中的进程ID
   */
  public getRunningProcessIds(): string[] {
    return Array.from(this.runningProcesses.keys());
  }
}